/**
 * 账号选择对话框主体
 */
import { SearchOutlined } from '@ant-design/icons'
import { Spin, Button, Input, type InputRef } from 'antd'
import type { OrderedSet } from 'immutable'
import { EditModal } from '@/desktop/components'
import type { BaseAccount } from '@/services/auth'
import { useChoosing, useSearch, type ChoosingProps } from '../hooks'
import './index.module.less'

import Groups from './Groups'
import MultiChoosed from './MultiChoosed'
import SearchedAccounts from './SearchedAccounts'
import SingleChoosed from './SingleChoosed'

type ModalOnlyProps = {
  multiple?: boolean // 单选还是多选，默认为单选
  visible: boolean
  title?: string

  // 完成选择时会触发此回调，传参是选中的账号数组：
  // 1. 无论单选还是多选都是数组
  // 2. 至少有一个账号（因为没选择账号的情况下不允许提交）
  // 3. 数组里不含 lockChoosed props 指定的账号
  // 此回调可返回一个 Promise，对话框会显示对应的“处理中”状态
  onChoosed: (accounts: [BaseAccount] & BaseAccount[]) => void | Promise<void>
  onCancel: () => void
}

export function ChooseAccountModal(props: ChoosingProps & ModalOnlyProps) {
  const { visible, title, multiple = false, onCancel } = props

  return <EditModal
    styleName={`modal ${multiple ? 'multiple' : 'single'}`}
    title={title ?? null}
    width={multiple ? '650px' : '520px'}
    open={visible}
    closable={false}
    onCancel={onCancel}
  >
    {visible ? <ModalContent {...props} multiple={multiple} /> : null}
  </EditModal>
}

function ModalContent(
  props: ChoosingProps & Pick<Required<ModalOnlyProps>, 'multiple' | 'onChoosed' | 'onCancel'>,
) {
  const { multiple, onChoosed, onCancel, ...choosingProps } = props
  const { choosed, setChoosed, locked, accountsData } = useChoosing(choosingProps)
  const { keyword, keywordOnChange, search, searchedAccounts } = useSearch(
    accountsData?.map ?? null,
  )

  const inputRef = useRef<InputRef>(null)
  function searchSetChoosed(choosed: OrderedSet<string>) {
    setChoosed(choosed)
    // 在搜索界面里选中或取消选中一个人后便离开搜索模式，同时让搜索框重新获得焦点
    search('')
    inputRef.current?.focus()
  }

  const canSubmit = !!accountsData && !!choosed.size
  const [submitting, setSubmitting] = useState(false)
  async function confirmOnChoosed() {
    if (!canSubmit) return

    // accountsData 有值的情况下，useChoosing() 保证了 choosed 的账号一定会在 map 里出现
    const accounts = [...choosed].map(id => accountsData.map.get(id)!) as [BaseAccount] &
      BaseAccount[]
    const res = onChoosed(accounts)

    if (res) {
      setSubmitting(true)
      await res
      setSubmitting(false)
    }
  }

  if (!accountsData) {
    return <div styleName="loading">
      <Spin size="large" />
      <Button onClick={onCancel}>取消</Button>
    </div>
  }

  const choosing = <>
    <header styleName="search">
      <Input
        prefix={<SearchOutlined />}
        placeholder="搜索"
        value={keyword}
        onChange={keywordOnChange}
        ref={inputRef}
      />
    </header>

    {searchedAccounts !== null ? (
      <SearchedAccounts
        accounts={searchedAccounts}
        multiple={multiple}
        locked={locked}
        choosed={choosed}
        setChoosed={searchSetChoosed}
      />
    ) : (
      <Groups
        multiple={multiple}
        locked={locked}
        choosed={choosed}
        accountsData={accountsData}
        setChoosed={setChoosed}
      />
    )}
  </>

  const footer = <Footer
    submitting={submitting}
    onCancel={onCancel}
    onConfirm={canSubmit ? confirmOnChoosed : undefined}
  />

  if (multiple) {
    return <div styleName="content">
      <aside>{choosing}</aside>
      <main>
        {<MultiChoosed choosed={choosed} setChoosed={setChoosed} accountMap={accountsData.map} />}
        {footer}
      </main>
    </div>
  } else {
    return <>
      <div styleName="content">
        {choosing}
        <SingleChoosed choosed={choosed} accountMap={accountsData.map} />
      </div>
      {footer}
    </>
  }
}

function Footer(props: { submitting: boolean; onCancel: () => void; onConfirm?: () => void }) {
  const { submitting, onCancel, onConfirm } = props
  return <footer>
    <Button onClick={onCancel}>取消</Button>
    <Button type="primary" loading={submitting} disabled={!onConfirm} onClick={onConfirm}>
      确定
    </Button>
  </footer>
}
